/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#pragma once

#include "Utility/Algebra/Matrix.h"
#include "Utility/Logging/SGLogger.h"

#include "DataStructure/Common/Id.h"

#include "DBManager/Common/DBManagerNamespace.h"
#include "DBManager/DBServiceFactory.h"
#include "DBManager/Database/HDF5Database.h"

SG_DBMANAGER_NAMESPACE_OPEN

/**
 * @brief    复制模型某表数据，适用于通过FindById查找数据的表
 *
 * @tparam IService
 * @param    src 源数据库
 * @param    dest 目标数据库
 * @param    id 数据条目ID
 * @return
 * @author   wuxingchuang
 * @date     2025.03.10
 */
template <class IService>
SG::DataStructure::Common::Status CopyDataUnique (SG::DBManager::DBServiceFactory* const     src,
                                                  SG::DBManager::DBServiceFactory* const     dest,
                                                  std::vector<SG::DataStructure::Common::Id> ids)

{
    auto serviceSrc  = src->get<IService> ();
    auto serviceDest = dest->get<IService> ();

    std::vector<typename IService::ServiceDataType> entities (ids.size ());

    for (size_t i = 0; i < entities.size (); i++)
    {
        serviceSrc->FindById (ids[i], entities[i]);
    }

    return serviceDest->MAdd (entities);
}

/**
 * @brief    复制分区结果某表数据，适用于通过DOMAIN_ID分区的表格， 使用DOMAIN_ID查找数据并添加到目标数据库
 *
 * @tparam IService
 * @param    srcs 分区数据库
 * @param    dest 目标数据库
 * @param    domainIds
 * @param    rankSize
 * @return
 * @author   wuxingchuang
 * @date     2025.03.10
 */
template <class IService>
SG::DataStructure::Common::Status CopyDataResult (std::vector<std::shared_ptr<DBServiceFactory>> srcs,
                                                  std::shared_ptr<DBServiceFactory>              dest,
                                                  std::vector<SG::DataStructure::Common::Id>     domainIds)

{
    auto disp = dest->get<IService> ();

    for (size_t i = 0; i < srcs.size (); i++)
    {
        auto dispx = srcs[i]->get<IService> ();
        for (auto&& id : domainIds)
        {
            std::vector<typename decltype (disp)::element_type::ServiceDataType> results;
            if (dispx->Find (id, results) == SG::DataStructure::Common::Status::STATUS_Success)
            {
                disp->AddByDomainId (id, results);
            }
        }
    }
    return SG::DataStructure::Common::Status::STATUS_Success;
}

// 判断是否有 pid 成员
template <typename T>
class has_pid
{
  private:
    template <typename U>
    static auto test (int) -> decltype (std::declval<U> ().m_pId, std::true_type ());
    template <typename>
    static std::false_type test (...);

  public:
    static constexpr bool value = decltype (test<T> (0))::value;
};

// 注册操作
template <typename DataType, class RepositoryType>
typename std::enable_if<has_pid<DataType>::value, bool>::type RegisterP2E ()
{
    SG::DBManager::HDF5Hub::ConnectGetP2E (
        [] (SG::DBManager::IDatabase* database) -> std::map<SG::DataStructure::Common::I64, std::vector<SG::DataStructure::Common::Id>> {
            std::shared_ptr<RepositoryType> repository = database->GetRepository<RepositoryType> ();

            std::map<SG::DataStructure::Common::I64, std::vector<SG::DataStructure::Common::Id>> result;
            for (DataType& i : repository->GetAllData ())
            {
                if (result.find (i.m_pId) == result.end ())
                {
                    result[i.m_pId] = { i.m_id };
                }
                else
                {
                    result[i.m_pId].emplace_back (i.m_id);
                }
            }

            return result;
        });

    return true;
}

template <typename DataType, typename RepositoryType>
typename std::enable_if<!has_pid<DataType>::value, bool>::type RegisterP2E ()
{
    return true;
}

/// @brief 获取某单元节点列表
template <typename TRepositoryType>
std::vector<SG::DataStructure::Common::Id> FindElementNodes (TRepositoryType* repository, SG::DataStructure::Common::Id eid)
{
    std::size_t nodeSize = repository->GetCurrentTypeNodeSize ();

    std::vector<SG::DataStructure::Common::Id> result;
    result.resize (nodeSize);

    typename TRepositoryType::DataType data;

    SG::DataStructure::Common::Status status = repository->FindById (eid, data);

    if (status == SG::DataStructure::Common::Status::STATUS_Success)
    {
        for (size_t i = 0; i < nodeSize; i++)
        {
            result[i] = data.m_g[i];
        }
    }
    return result;
}

/// @brief 组装单元节点矩阵
template <typename IRepositoryType>
auto AssembleElementNodes (SG::DBManager::IDatabase* database) -> SG::Algebra::Matrix
{
    std::shared_ptr<IRepositoryType> repos = database->GetRepository<IRepositoryType> ();

    std::size_t const eleSize  = repos->Size ();
    std::size_t const nodeSize = IRepositoryType::GetCurrentTypeNodeSize ();

    // 节点矩阵
    SG::Algebra::Matrix nodes (eleSize, nodeSize);

    typename IRepositoryType::DataType temp;
    // 遍历所有单元
    for (size_t index = 0; index < eleSize; index++)
    {
        // 获取单元节点
        if (repos->FindByIndex (index, temp) == SG::DataStructure::Common::Status::STATUS_Success)
        {
            // 遍历节点
            for (std::size_t j = 0; j < nodeSize; j++)
            {
                nodes (index, j) = static_cast<SG::DataStructure::Common::Real> (temp.m_g[j]);
            }
        }
    }

    return nodes;
};

SG_DBMANAGER_NAMESPACE_CLOSE
